package com.zc.manager.network.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.zc.common.core.foreignkeyservice.AssociatedService;
import com.zc.common.core.foreignkeyservice.ForeignKeyService;
import com.zc.common.core.foreignkeyservice.LinkModel;
import com.zc.component.gateway.DeviceGateway;
import com.zc.component.gateway.DeviceGatewayManager;
import com.zc.component.gateway.supports.DeviceGatewayProperties;
import com.zc.component.gateway.supports.DeviceGatewayPropertiesManager;
import com.zc.manager.network.domain.IotDeviceGateway;
import com.zc.manager.network.mapper.IotDeviceGatewayMapper;
import com.zc.manager.network.service.IotDeviceGatewayService;
import com.zc.web.exception.NotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * 设备网关Service业务层处理
 *
 * @author zhaoxianglong
 * @date 2022-11-7
 */
@Service
public class IotDeviceGatewayServiceImpl
        extends ServiceImpl<IotDeviceGatewayMapper, IotDeviceGateway>
        implements IotDeviceGatewayService, DeviceGatewayPropertiesManager, AssociatedService, ForeignKeyService {

    @Resource
    private IotDeviceGatewayMapper iotDeviceGatewayMapper;

    @Resource
    private DeviceGatewayManager gatewayManager;

    @Resource(name = "iotNetworkConfigServiceImpl")
    private AssociatedService associatedService;

    @PostConstruct
    public void init() {
        // 注册外键
        registerForeignKey();
    }

    /**
     * 查询设备网关列表
     */
    @Override
    public List<IotDeviceGateway> selectIotDeviceGatewayList(IotDeviceGateway iotDeviceGateway) {
        return iotDeviceGatewayMapper.selectIotDeviceGatewayList(iotDeviceGateway);
    }

    /**
     * 根据启动状态查询设备网关信息
     *
     * @param startState 启停状态
     * @return
     */
    @Override
    public List<IotDeviceGateway> selectIotDeviceGatewayByStartState(String startState) {
        LambdaQueryWrapper<IotDeviceGateway> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(IotDeviceGateway::getStartState, startState);
        return list(queryWrapper);
    }

    /**
     * 新增
     */
    @Override
    public boolean addDeviceGateway(IotDeviceGateway iotDeviceGateway) {
        iotDeviceGateway.setStartState(IotDeviceGateway.DISABLED);
        iotDeviceGateway.setCreateTime(new Date());
        return save(iotDeviceGateway);
    }

    /**
     * 修改
     */
    @Override
    public boolean editDeviceGateway(IotDeviceGateway iotDeviceGateway) {
        iotDeviceGateway.setUpdateTime(new Date());
        return updateById(iotDeviceGateway);
    }

    /**
     * 查询指定设备网关
     */
    @Override
    public IotDeviceGateway getDeviceGateway(Long id) {
        return getById(id);
    }


    /**
     * 状态修改：启动
     */
    @Override
    @Transactional
    public boolean startupDeviceGateway(Long id) {

        IotDeviceGateway deviceGateway = getById(id);

        if (deviceGateway == null) {
            throw new ServiceException("无法获取当前网关设备信息", HttpStatus.NOT_FOUND);
        }

        // 启动设备网关
        gatewayManager
                .getGateway(String.valueOf(deviceGateway.getId()))
                .flatMap(DeviceGateway::startup)
                .block();

        IotDeviceGateway iotDeviceGateway = new IotDeviceGateway();
        BeanUtils.copyBeanProp(iotDeviceGateway, deviceGateway);
        iotDeviceGateway.setStartState(IotDeviceGateway.ENABLED);
        iotDeviceGateway.setId(id);
        return updateById(iotDeviceGateway);
    }

    /**
     * 状态修改：停止
     */
    @Override
    @Transactional
    public boolean shutdownDeviceGateway(Long id) {
        IotDeviceGateway deviceGateway = getById(id);

        if (deviceGateway == null) {
            throw new ServiceException("无法获取当前网关设备信息", HttpStatus.NOT_FOUND);
        }

        // 停止设备网关
        gatewayManager
                .shutdown(String.valueOf(id))
                .block();

        IotDeviceGateway iotDeviceGateway = new IotDeviceGateway();
        BeanUtils.copyBeanProp(iotDeviceGateway, deviceGateway);
        iotDeviceGateway.setStartState(IotDeviceGateway.DISABLED);
        iotDeviceGateway.setId(id);
        return updateById(iotDeviceGateway);
    }


    /**
     * 根据提供的ID列表删除相关记录。
     *
     * @param ids 要删除的记录的ID列表，类型为List<Long>。
     * @return 返回一个布尔值，表示是否成功删除了记录。在这个实现中，总是返回false。
     */
    @Override
    public boolean removeByIds(List<Long> ids) {

        List<IotDeviceGateway> deviceGateways = listByIds(ids);

        for (IotDeviceGateway deviceGateway : deviceGateways) {
            if (IotDeviceGateway.ENABLED.equals(deviceGateway.getStartState())) {
                throw new ServiceException(deviceGateway.getGatewayName() + ":服务网关已启用，不能删除！");
            }
        }

        return super.removeByIds(ids);
    }

    /**
     * 获取网关的属性
     *
     * @param id 网关ID
     * @return 网关属性
     */
    @Override
    public Mono<DeviceGatewayProperties> getProperties(String id) {

        return Mono.just(getDeviceGateway(Long.parseLong(id)))
                .switchIfEmpty(Mono.error(() -> new NotFoundException("该设备网关不存在")))
                .map(IotDeviceGateway::toDeviceGatewayProperties);
    }

    /**
     * 通过外键值查找本实体，如果查找到则说明本实体关联了外键对应的实体。
     *
     * @param foreignKey      ： 本实体外键属性
     * @param foreignKeyValue ： 本实体的外键值
     * @return
     */
    @Override
    public LinkModel findByForeignKey(String foreignKey, Object foreignKeyValue) {

        if (FOREIGN_KEY_NETWORK_ID.equals(foreignKey)) {
            LambdaQueryWrapper<IotDeviceGateway> queryWrapper = new LambdaQueryWrapper<>();

            queryWrapper.eq(IotDeviceGateway::getNetworkId, foreignKeyValue);

            List<IotDeviceGateway> iotDeviceGatewayList = list(queryWrapper);

            if (iotDeviceGatewayList != null && !iotDeviceGatewayList.isEmpty()) {
                return new LinkModel("设备网关已关联");
            }
        }

        return null;
    }

    /**
     * 根据外键删除所有关联数据
     *
     * @param foreignKey      ： 本实体外键属性
     * @param foreignKeyValue ： 本实体的外键值
     * @return
     */
    @Override
    public boolean deleteAllByForeignKey(String foreignKey, Object foreignKeyValue) {
        return false;
    }

    /**
     * 外键标识
     */
    private static final String FOREIGN_KEY_NETWORK_ID = "networkId";

    /**
     * 如果实体存在外键关联，则向外该键所指的实体服务注册外键，从而建立关联链关系。
     */
    @Override
    public void registerForeignKey() {
        associatedService.registerForeignKey(this, FOREIGN_KEY_NETWORK_ID);
    }
}
